#include "format_wav.h"
#include "audio_player.h"
#include "esp_log.h"
#include <stdio.h>
#include <string.h>
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"

#define TAG     "PLAYER"

typedef struct
{
    char path[32];
    audio_player_write_handler_t write_handle;
    audio_player_play_start_cb_t start_cb;
    audio_player_play_finish_cb_t finish_cb;
}audio_cmd_t;
static QueueHandle_t    audio_queue = NULL;
static SemaphoreHandle_t    audio_stop_sem = NULL;

bool verify_wav(wav_header_t *wav_header)
{
    if(memcmp(wav_header->descriptor_chunk.chunk_id,"RIFF",0) != 0)
    {
        ESP_LOGI(TAG,"wav file chunk id invaild!,value is %s",wav_header->descriptor_chunk.chunk_id);
        return false;
    }
    if(memcmp(wav_header->fmt_chunk.subchunk_id,"fmt",0) != 0)
    {
        ESP_LOGI(TAG,"wav file chunk id invaild!,value is %s",wav_header->fmt_chunk.subchunk_id);
        return false;
    }
    if(memcmp(wav_header->data_chunk.subchunk_id,"data",0) != 0)
    {
        ESP_LOGI(TAG,"wav file chunk id invaild!,value is %s",wav_header->data_chunk.subchunk_id);
        return false;
    }
    return true;
}

typedef enum
{
    AUDIO_PLAYER_STATE_IDLE,
    AUDIO_PLAYER_STATE_PLAY,
}AUDIO_PLAYER_STATE;

static void audio_player_task(void* param)
{
    audio_cmd_t cmd;
    const size_t tx_buf_len = 4096;             //每次播放的音频长度（字节）
    uint8_t *read_buf = malloc(tx_buf_len);     //从文件中读取的音频内存数据
    size_t rx_len = 0;                          //记录已播放的数据长度（字节）
    wav_header_t wav_header;                    //wav头
    FILE *wav_file = NULL;
    AUDIO_PLAYER_STATE  state = AUDIO_PLAYER_STATE_IDLE;
    while(1)
    {
        if(state == AUDIO_PLAYER_STATE_PLAY)
        {
            BaseType_t sem_ret = xSemaphoreTake(audio_stop_sem,pdMS_TO_TICKS(20));
            if(sem_ret != pdFALSE || rx_len >= wav_header.data_chunk.subchunk_size)
            {
                 ESP_LOGI(TAG,"Finish play");
                if(wav_file)
                {
                    fclose(wav_file);
                    wav_file = NULL;
                }
                rx_len = 0;
                state = AUDIO_PLAYER_STATE_IDLE;
                if(cmd.finish_cb)
                    cmd.finish_cb(1);
            }
            else
            {
                size_t real_buf_size = 0;
                if(rx_len + tx_buf_len < wav_header.data_chunk.subchunk_size)
                    real_buf_size = tx_buf_len;
                else
                    real_buf_size = wav_header.data_chunk.subchunk_size - rx_len;
                fread(read_buf,real_buf_size,1,wav_file);
                if(cmd.write_handle)
                    cmd.write_handle((const int16_t*)read_buf,real_buf_size/2);
                rx_len += real_buf_size;
            }
        }
        else if(state == AUDIO_PLAYER_STATE_IDLE)
        {
            BaseType_t ret = xQueueReceive(audio_queue,&cmd,pdMS_TO_TICKS(5000));
            if(ret)
            {
                wav_file = fopen(cmd.path,"r");
                if(!wav_file)
                {
                    ESP_LOGI(TAG,"Can't find filename:%s",cmd.path);
                    continue;
                }
                ESP_LOGI(TAG,"Start play file:%s",cmd.path);
                fread(&wav_header,sizeof(wav_header),1,wav_file);
                if(!verify_wav(&wav_header))
                {
                    fclose(wav_file);
                    continue;
                }
                state = AUDIO_PLAYER_STATE_PLAY;
                if(cmd.start_cb)
                    cmd.start_cb(1);
            }
        }
    }
}

void audio_player_play(const char* path,
        audio_player_write_handler_t write_handle,
        audio_player_play_start_cb_t start_cb,
        audio_player_play_finish_cb_t finish_cb
        )
{
    if(!audio_queue)
    {
        audio_queue = xQueueCreate(3,sizeof(audio_cmd_t));
        audio_stop_sem = xSemaphoreCreateBinary();
        xTaskCreatePinnedToCore(audio_player_task,"audio",4096,NULL,3,NULL,1);
    }
    audio_cmd_t cmd;
    snprintf(cmd.path,32,"%s",path);
    cmd.start_cb = start_cb;
    cmd.write_handle = write_handle;
    cmd.finish_cb = finish_cb;
    xQueueSend(audio_queue,&cmd,portMAX_DELAY);
}

void audio_player_stop(void)
{
    xSemaphoreGive(audio_stop_sem);
}

